package com.springboot.wisdom.common.exception;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import com.springboot.wisdom.common.common.ResultUtil;
import com.springboot.wisdom.common.common.bean.MyResult;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.core.annotation.Order;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.io.IOException;
import java.sql.SQLSyntaxErrorException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 全局异常处理器。
 */
@Component
@RestControllerAdvice
@Order(100)
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(MqttException.class)
    public MyResult<String> requestTypeErrorHandler(HttpServletRequest request, MqttException exception) {
        log.error("异常信息：{}", exception.getMessage());
        return ResultUtil.error(exception.getMessage());
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public MyResult<String> requestTypeErrorHandler(HttpServletRequest request, IllegalArgumentException exception) {
        try {
            log.error("异常信息：{}", exception.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
        return ResultUtil.error("参数有误！");
    }


    @ExceptionHandler(SQLSyntaxErrorException.class)
    public MyResult<String> requestTypeErrorHandler(HttpServletRequest request, SQLSyntaxErrorException exception) {
        log.error("异常信息：{}", exception.getMessage());
        return ResultUtil.error("后台服务器SQL出问题啦！快联系管理员！");
    }

    /**
     * Sa-Token 未登录。
     * 必须在路由拦截中拦截  /error/** 路径才能正常拦截。
     *
     * @param request
     * @param exception
     * @return
     */
    @ExceptionHandler(NotLoginException.class)
    public MyResult<String> requestTypeErrorHandler(HttpServletRequest request, NotLoginException exception) {
        log.error("异常信息：{}", exception.getMessage());
        return ResultUtil.error("请登录！");
    }

    /**
     * 无权限。
     *
     * @param request
     * @param exception
     * @return
     */
    @ExceptionHandler(NotPermissionException.class)
    public MyResult<String> requestTypeErrorHandler(HttpServletRequest request, NotPermissionException exception) {
        log.error("异常信息：{}", exception.getMessage());
        return ResultUtil.error("权限不足！");
    }

    /**
     * 无此角色：XXXX。
     *
     * @param request
     * @param exception
     * @return
     */
    @ExceptionHandler(NotRoleException.class)
    public MyResult<String> requestTypeErrorHandler(HttpServletRequest request, NotRoleException exception) {
        log.error("异常信息：{}", exception.getMessage());
        return ResultUtil.error("权限不足！");
    }

    /**
     * 请求类型异常。
     *
     * @param request
     * @param exception
     * @return
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public MyResult<String> requestTypeErrorHandler(HttpServletRequest request, HttpMessageNotReadableException exception) throws IOException {
        log.error("异常信息：{}", exception.getMessage());
        if (Objects.requireNonNull(exception.getMessage()).startsWith("JSON parse error:")) {
            return ResultUtil.error("400",
                    "JSON 格式转换失败！", null);
        }
        return ResultUtil.error(exception.getMessage());
    }

    /**
     * 参数校验失败
     *
     * @param ex
     * @return
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public MyResult<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, HttpServletRequest request) {
        Map<String, String> result = new HashMap<>();
        BindingResult bindingResult = ex.getBindingResult();
        log.error("请求[ {} ] {} 的参数校验发生错误！", request.getMethod(), request.getRequestURL());
        for (ObjectError objectError : bindingResult.getAllErrors()) {
            FieldError fieldError = (FieldError) objectError;
            log.error("参数 {} = {} 校验错误：{}", fieldError.getField(), fieldError.getRejectedValue(), fieldError.getDefaultMessage());
            result.put(fieldError.getField(), fieldError.getDefaultMessage());
            return ResultUtil.error("4000", fieldError.getDefaultMessage(), null);
        }
        return ResultUtil.error("4000", "参数校验失败", result);
    }

    /**
     * 参数校验失败。用于注解校验。
     *
     * @param ex
     * @return
     */
    @ExceptionHandler({ConstraintViolationException.class})
    public MyResult<String> handleConstraintViolationException(ConstraintViolationException ex) {
        String[] split = ex.getMessage().split(":");
        log.error("异常信息：{}", ex.getMessage());
        return ResultUtil.error("4000", split.length == 0 ? ex.getMessage() : split[1].trim(), null);
    }

//    // 全局异常拦截。
//    @ExceptionHandler
//    public MyResult<String> requestTypeErrorHandler(HttpServletRequest request, Exception exception) {
//            log.error("异常信息：{}", exception.getMessage());
//        return ResultUtil.error(exception.getMessage());
//    }

    @ExceptionHandler({Exception.class})
    public MyResult<String> handlerException(Exception e) {
        e.printStackTrace();
        log.error("异常信息：{}", e.getMessage());
        return ResultUtil.error(e.getMessage());
    }
}